package com.dieusoft.box.bill.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dieusoft.box.bill.entity.BillInfo;
import com.dieusoft.box.bill.service.IBillInfoService;
import com.dieusoft.box.bill.vo.BillInfoVO;
import com.dieusoft.box.trade.entity.CostInfo;
import com.dieusoft.box.trade.service.ICostInfoService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.aspect.annotation.PermissionData;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @Description: 账单信息
 * @Author: dongw
 * @Date: 2020-10-22
 * @Version: V1.0
 */
@Api(tags = "账单信息")
@RestController
@RequestMapping("/box.bill")
@Slf4j
public class BillController {

    @Autowired
    private IBillInfoService billInfoService;

    @Autowired
    private ICostInfoService costInfoService;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");


    /**
     * 分页列表查询
     *
     * @param billInfo
     * @param pageNo
     * @param pageSize
     * @param req
     * @return
     */
    @PermissionData(pageComponent = "bill/BillInfoList")
    @AutoLog(value = "账单信息-分页列表查询")
    @ApiOperation(value = "账单信息-分页列表查询", notes = "账单信息-分页列表查询")
    @GetMapping(value = "/list")
    public Result<?> queryPageList(BillInfo billInfo,
                                   @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                   @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                                   HttpServletRequest req) {
        QueryWrapper<BillInfo> queryWrapper = QueryGenerator.initQueryWrapper(billInfo, req.getParameterMap());
        Page<BillInfo> page = new Page<BillInfo>(pageNo, pageSize);
        IPage<BillInfo> pageList = billInfoService.page(page, queryWrapper);
        return Result.OK(pageList);
    }

    /**
     * 账单核销
     *
     * @return
     */
    @AutoLog(value = "账单核销")
    @ApiOperation(value = "账单核销", notes = "账单核销")
    @PostMapping(value = "/verification")
    @Transactional(rollbackOn = Exception.class)
    public Result verification(@RequestBody BillInfo billInfo) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
//        billInfo.setUpdateTime(new Date());
        billInfo.setStatus(billInfo.getVerificationType().equals("all") ? "4" : "3");
        billInfo.setUpdateUser(sysUser.getUsername());
        BillInfo byId = billInfoService.getById(billInfo.getId());
        billInfo.setBillingTime(byId.getBillingTime());
        if (billInfo.getVerificationType().equals("part")) {
            BigDecimal writeOffPrice = new BigDecimal(StringUtils.isBlank(byId.getWriteOffAmount()) ? "0" : byId.getWriteOffAmount());
            BigDecimal currentWriteOffPrice = new BigDecimal(billInfo.getWriteOffAmount());
            billInfo.setWriteOffAmount(writeOffPrice.add(currentWriteOffPrice).toString());
        } else {
            billInfo.setWriteOffAmount(byId.getAmount());
        }
        //更新账单信息
        billInfoService.updateById(billInfo);
        //更新费用信息
        costInfoService.updateByBillNumber(
                billInfo.getBillNumber(),
                sysUser.getUsername(),
                billInfo.getVerificationType().equals("all") ? "已开票已核销" : "已开票部分核销",
                byId.getInvoiceNumber());
        return Result.OK("操作成功", null);
    }


    /**
     * 通过id删除
     *
     * @param id
     * @return
     */
    @AutoLog(value = "通过id删除")
    @ApiOperation(value = "通过id删除", notes = "通过id删除")
    @DeleteMapping(value = "/delete")
    @Transactional(rollbackOn = Exception.class)
    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
        Optional<BillInfo> billInfoOptional = Optional.ofNullable(billInfoService.getById(id));
        if (billInfoOptional.isPresent()) {
            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
            //根据账单号重置费用信息数据
            costInfoService.resetByBillNumber(
                    billInfoOptional.get().getBillNumber(),
                    sysUser.getUsername(),
                    "账单未建立",
                    "");
            //删除账单信息
            billInfoService.removeById(id);
        }

        return Result.OK("删除成功!");
    }

    /**
     * 录入发票
     *
     * @return
     */
    @AutoLog(value = "录入发票")
    @ApiOperation(value = "录入发票", notes = "录入发票")
    @PostMapping(value = "/save/invoice")
    @Transactional(rollbackOn = Exception.class)
    public Result saveInvoice(@RequestParam("ids") String ids,
                              @RequestParam("invoiceNumber") String invoiceNumber,
                              @RequestParam("billingTime") String billingTime) throws ParseException {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        Date billingDate = sdf.parse(billingTime);
//        final Date date = new Date();
        String[] split = ids.split(",");
        List<String> listIds = Arrays.asList(split);
        List<BillInfo> billInfoList = new ArrayList<>();
        listIds.stream().forEach(item -> {
            Optional<BillInfo> billInfoOptional = Optional.ofNullable(billInfoService.getById(item));
            if (billInfoOptional.isPresent()) {
                BillInfo billInfo = billInfoOptional.get();
                billInfo.setUpdateUser(sysUser.getUsername());
//                billInfo.setUpdateTime(date);
                billInfo.setStatus("2");
                billInfo.setBillingTime(billingDate);
                billInfo.setInvoiceNumber(invoiceNumber);
                billInfoList.add(billInfo);
            }
        });
        if (billInfoList.size() != listIds.size()) {
            return Result.error("取消核销的账单中有不存在的数据，请重新操作");
        }
        billInfoService.updateBatchById(billInfoList);
        costInfoService.updateByBillNumber(
                billInfoList.get(0).getBillNumber(),
                sysUser.getUsername(),
                "已开票未核销",
                invoiceNumber);
        return Result.OK("发票录入成功", null);
    }

    /**
     * 修改/作废发票
     *
     * @return
     */
    @AutoLog(value = "修改/作废发票")
    @ApiOperation(value = "修改/作废发票", notes = "修改/作废发票")
    @PostMapping(value = "/update/invoice")
    @Transactional(rollbackOn = Exception.class)
    public Result updateInvoice(@RequestParam("id") String id,
                                @RequestParam("invoiceNumber") String invoiceNumber,
                                @RequestParam("billingTime") String billingTime,
                                @RequestParam("flag") Integer flag) throws ParseException {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        Optional<BillInfo> billInfoOptional = Optional.ofNullable(billInfoService.getById(id));
        if (!billInfoOptional.isPresent()) {
            return Result.error("账单数据不存在");
        }
        BillInfo billInfo = billInfoOptional.get();
//        final Date date = new Date();
        //修改发票
        if (flag == 1) {
            Date billingDate = sdf.parse(billingTime);
            billInfo.setUpdateTime(new Date());
            billInfo.setUpdateUser(sysUser.getUsername());
            billInfo.setInvoiceNumber(invoiceNumber);
            billInfo.setBillingTime(billingDate);
            billInfo.setVerificationTime(null);
            billInfo.setVerificationType("");
            billInfo.setVerificationRate("");
            billInfo.setVerificationMode("");
            billInfo.setVerificationCurrency("");
            billInfo.setVerificationAccount("");
            billInfoService.updateById(billInfo);
            List<CostInfo> costInfos = costInfoService.selectByBillNumber(billInfo.getBillNumber());
            costInfos.stream().forEach(item -> {
                item.setUpdateBy(sysUser.getUsername());
//                item.setUpdateTime(date);
                item.setInvoiceNumber(invoiceNumber);
            });
            costInfoService.updateBatchById(costInfos);
            return Result.OK("发票修改成功", null);
        } else {
            billInfo.setStatus("1");
            billInfo.setUpdateUser(sysUser.getUsername());
//            billInfo.setUpdateTime(date);
            billInfo.setInvoiceNumber("");
            billInfo.setBillingTime(null);
            billInfoService.updateById(billInfo);
            List<CostInfo> costInfos = costInfoService.selectByBillNumber(billInfo.getBillNumber());
            costInfos.stream().forEach(item -> {
                item.setUpdateBy(sysUser.getUsername());
//                item.setUpdateTime(date);
                item.setInvoiceNumber(null);
                item.setStatus("未开票未核销");
            });
            costInfoService.updateBatchById(costInfos);
            return Result.OK("发票已作废", null);
        }
    }

    /**
     * 取消核销
     *
     * @return
     */
    @AutoLog(value = "取消核销")
    @ApiOperation(value = "取消核销", notes = "取消核销")
    @PostMapping(value = "/cancel/verification")
    @Transactional(rollbackOn = Exception.class)
    public Result cancelVerification(String ids) {
        if (StringUtils.isBlank(ids)) {
            return Result.error("没有需要操作的数据");
        }
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        final Date date = new Date();
        String[] split = ids.split(",");
        List<String> listIds = Arrays.asList(split);
        List<BillInfo> billInfoList = new ArrayList<>();
        listIds.stream().forEach(item -> {
            Optional<BillInfo> billInfoOptional = Optional.ofNullable(billInfoService.getById(item));
            if (billInfoOptional.isPresent()) {
                BillInfo billInfo = billInfoOptional.get();
                billInfo.setUpdateUser(sysUser.getUsername());
                billInfo.setUpdateTime(date);
                billInfo.setStatus("2");
                billInfo.setVerificationAccount("");
                billInfo.setVerificationCurrency("");
                billInfo.setVerificationMode("");
                billInfo.setVerificationRate("");
                billInfo.setVerificationTime(date);
                billInfo.setVerificationType("");
                billInfo.setWriteOffAmount("");
                billInfoList.add(billInfo);
            }
        });
        if (billInfoList.size() != listIds.size()) {
            return Result.error("取消核销的账单中有不存在的数据，请重新操作");
        }
        billInfoService.updateBatchById(billInfoList);
        costInfoService.updateByBillNumber(
                billInfoList.get(0).getBillNumber(),
                sysUser.getUsername(),
                "已开票未核销",
                "");
        return Result.OK("取消核销成功", null);
    }

    /**
     * 创建账单
     *
     * @return
     */
    @AutoLog(value = "创建账单")
    @ApiOperation(value = "创建账单", notes = "创建账单")
    @PostMapping(value = "/save")
    @Transactional(rollbackOn = Exception.class)
    public Result save(@RequestBody BillInfoVO billInfoVO) {
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //新增账单信息
        String billNumber = getBillNumber();
        BillInfo billInfo = new BillInfo();
        String idStr = IdWorker.getIdStr();
        BeanUtils.copyProperties(billInfoVO, billInfo);
        billInfo.setBillNumber(billNumber);
        billInfo.setId(idStr);
        billInfo.setCreateTime(new Date());
        billInfo.setCreateUser(sysUser.getUsername());
        billInfo.setSysOrgCode(sysUser.getOrgCode());
        //结算单位
        billInfo.setSettlementCompany(billInfoVO.getCostInfoList().get(0).getSettlementCompany());
        billInfoService.save(billInfo);
        //更新costInfo中的账单号
        billInfoVO.getCostInfoList().stream().forEach(item -> {
            CostInfo costInfo = costInfoService.getById(item.getId());
            BigDecimal cnyAmount = item.getTotalPrice().multiply(new BigDecimal(item.getRate()))
                    .setScale(2, BigDecimal.ROUND_HALF_UP);
            if (null == costInfo) {
                item.setBillNumber(billNumber);
                item.setCnyAmount(cnyAmount);
                item.setBillId(idStr);
                item.setStatus("未核销未开票");
                costInfoService.save(item);
            } else {
                costInfo.setBillNumber(billNumber);
                costInfo.setBillId(idStr);
                item.setCnyAmount(cnyAmount);
                costInfo.setStatus("未核销未开票");
                costInfoService.updateById(costInfo);
            }
        });
        return Result.OK("账单创建成功", billNumber);
    }

    /**
     * 生成账单号
     *
     * @return
     */
    private synchronized String getBillNumber() {
        StringBuffer sb = new StringBuffer().append("BI");
        String yymmdd = DateTimeFormatter.ofPattern("yyMMdd").format(LocalDate.now());
        sb.append(yymmdd);
        String s = sb.toString();
        Integer count = billInfoService.selectCountByPrefix(s + "%");
        String billNumber = String.format("%0" + 4 + "d", count + 1);
        return sb.append(billNumber).toString();
    }

}
